// UTF-8 w/o BOM

#include <tadbg.h>
#include <res_def.h>
#include <func.h>
#include <DAL.h>
#include "elf.h"
#include "gdi.h"
#include "font.h"
//#include <.h>
//#include ".h"


////////////////////////////////////////////////////////////////////////////////

static	UINT32	AppStart(EVENT_STACK_T* ev_st, REG_ID_T reg_id, UINT32 param2);
static	UINT32	AppExit(EVENT_STACK_T* ev_st, APPLICATION_T* app);

//static	UINT32	MainStateEnter(EVENT_STACK_T *ev_st, APPLICATION_T *app, ENTER_STATE_TYPE_T type);
//static	UINT32	MainStateExit(EVENT_STACK_T *ev_st, APPLICATION_T *app, EXIT_STATE_TYPE_T type);

static	UINT32	HandleKeyPress(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleKeyRelease(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleExit(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleTimerExpiried(EVENT_STACK_T* ev_st, APPLICATION_T* app);
//static	UINT32	Handle( EVENT_STACK_T *ev_st,  APPLICATION_T *app );

static UINT32	ToggleMode(UINT8 *wmode);
static UINT32	PrintMode(UINT8 *wmode, BOOL started);
static KEY_CODES_T ReturnModeKey(UINT8 *wmode, UINT8 keycode);
static UINT32 	NotifySnd(APPLICATION_T *app);

static void displayCbk(const RECT_T* updatedRect);

////////////////////////////////////////////////////////////////////////////////

#define MAX_SZ_SIZE 255
#define KEY_PRESSED_LEN 2

#define KEY_TIMER_ID 0xEEC66
#define DRAW_TIMER_ID 0xEEC67

#define ELF_NAME "Fonarik"

// Название приложения. Длина строки именно такая и никакая иначе
const char	app_name[APP_NAME_LEN] = ELF_NAME; 

RECT_T		cbkRect = {0, 0, 176, 220};

UINT32		evcode_base;
ldrElf		elf;

UINT8		GDIMode = GDI_INACTIVE;
UINT32		GDITransColor = ATI_565RGB(255, 0, 255);
UINT32		GDIDefPatMode = AHIROP_PATCOPY;
UINT32		GDIDrawPatMode = AHIROP_PATCOPY;

AHIDEVCONTEXT_T	hDC;
AHISURFACE_T	hDisp, hDraw;

////////////////////////////////////////////////////////////////////////////////

UINT32			intensity = 1;
BOOL			kbdlight = false;

/* Config section */
UINT8       	mode = 0;

UINT32          draw_timeout = 50;

UINT8           key_pressed[KEY_PRESSED_LEN];
UINT8	    	key_toggle = KEY_SMART;
UINT32          key_timeout = 500;
UINT8           key_count = 0;

UINT8           text_count = 0;

UINT32		    cBg = ATI_565RGB(255, 255, 255);
UINT32		    cFg = ATI_565RGB(0, 0, 0);
UINT32          tCol = ATI_565RGB(255, 0, 255);

UINT32			key_timer;
UINT32			draw_timer;

////////////////////////////////////////////////////////////////////////////////


// Обработчики событий для каждого state-а

// Обработчики событий для APP_STATE_ANY (используется в любом state)
static EVENT_HANDLER_ENTRY_T any_state_handlers[] =
{
	{ EV_KEY_PRESS,			HandleKeyPress		},
	{ EV_KEY_RELEASE,		HandleKeyRelease	},
	{ EV_PM_API_EXIT,		HandleExit			},		// PM API: cmd EXIT
	
	// Список всегда должен заканчиватся такой записью
	{ STATE_HANDLERS_END,	NULL				}
};


static EVENT_HANDLER_ENTRY_T main_state_handlers[] =
{
	{ EV_TIMER_EXPIRED,		HandleTimerExpiried },
	
	// Список всегда должен заканчиватся такой записью
	{ STATE_HANDLERS_END,	NULL				}
};


////////////////////////////////////////////////////////////////////////////////


// Таблица соответствий обработчиков, состояний и функций входа-выхода из состояния.
// Порядок состояний такой же, как в enum-e
static const STATE_HANDLERS_ENTRY_T state_handling_table[] =
{
	{ APP_STATE_ANY,		// State
		NULL,				// Обработчик входа в state
		NULL,				// Обработчик выхода из state
		any_state_handlers	// Список обработчиков событий
	},

	{ APP_STATE_MAIN,
		NULL,				//MainStateEnter,
		NULL,				//MainStateExit,
		main_state_handlers
	}

};





// Это EntryPoint для всех эльфов, должна быть объявлена именно так
// uri - путь к эльфу (аналогично argv[0])
// params - параметры эльфа (аналогично остальным argv)
ldrElf* _start( WCHAR* uri, WCHAR* params ) {
	
	UINT32				status = RESULT_OK;
	UINT32				reserve;
	UINT8				i;
	
	// Чтоб компилер не ругался
	uri = uri;
	params = params;
	
	// Проверяем, а вдруг уже запущено?
	if (ldrIsLoaded((char*)app_name)) {
		cprint("\x87" ELF_NAME ":\x8c Already Loaded!\n");
		return NULL; // Нам не нужен второй экземпляр
	}
 
	for (i = 0; i < KEY_PRESSED_LEN; i++)
		key_pressed[i] = KEY_MULTIKEYS_PRESSED;
	
	evcode_base = ldrRequestEventBase();
	elf.evbase = evcode_base;
	
	// инитим таблицы ивентов
	reserve = evcode_base + 1;
	for (i = 0; i < sizeof(state_handling_table)/sizeof(STATE_HANDLERS_ENTRY_T); i++ ) {
		reserve = ldrInitEventHandlersTbl( (EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve );
	}
	
	// Регистрируем приложение
	status = APP_Register(	&evcode_base,			// На какое событие должно запускаться приложение
							1,						// Кол-во событий, на которое должно запускаться приложение
							state_handling_table,	// Таблица состояний
							APP_STATE_MAX,			// Количество состояний
							(void*)AppStart );		// Функция, вызываемая при запуске
	
	dbgf("Register: status = %d", status);
	
	elf.name = (char*)app_name;
	ldrSendEvent(evcode_base); // Запустить немедленно
	
	return &elf;
}





// Функция вызываемая при старте приложения
UINT32 AppStart(EVENT_STACK_T* ev_st,  REG_ID_T reg_id,  UINT32 param2) {
	
	APPLICATION_T		*app = NULL;
	UINT32				status = RESULT_OK;
	
	dbg("AppStart: Enter");
	
	// Инициализация для фоновых приложений
	app = (APPLICATION_T*)APP_InitAppData(	(void*)APP_HandleEventPrepost,	// Обработчик для фоновых приложений
											sizeof(APPLICATION_T),			// Размер структуры приложения
											reg_id,
											0, 0,
											1,
											AFW_APP_CENTRICITY_NONE,
											AFW_PREPROCESSING,
											AFW_POSITION_TOP );

	dbgf("AppStart: APP_InitAppData 0x%X", app);
	
	if ( !app )	{
		cprint("\x87" ELF_NAME ":\x8c Init Failed!\n");
		return ldrUnloadElf();
	}
	
	status = APP_Start( ev_st, app,
						APP_STATE_MAIN,			// Начальное состояние для фонового приложения
						state_handling_table,
						AppExit,
						app_name,
						0 );

	dbgf("AppStart: APP_Start, status = 0x%X", status);
	
	if ( status == RESULT_OK ) {
		elf.app = app;
		GDI_Init(&hDC, &hDisp, &hDraw, app_name, GDI_PRIVATEDC, AHIROP_PATCOPY, AHIROP_PATCOPY);	// Инициализация драйвера
		ldrDisplayCbkReg((dispCbk)displayCbk, &cbkRect, TRUE);										// Регистрация коллбека
		draw_timer = StartTimer(draw_timeout, DRAW_TIMER_ID, ttCyclical, app);  					// Старт таймера #2
	} else {
		cprint("\x87" ELF_NAME ":\x8c Start Failed!\n");
		APP_HandleFailedAppStart( ev_st, app, 0 );
		return ldrUnloadElf(); 
	}
	
	return RESULT_OK;
}





// Функция выхода из приложения
UINT32 AppExit( EVENT_STACK_T* ev_st,  APPLICATION_T* app ) {
	
	UINT32				status;

	if (key_timer != 0) { StopTimer(&key_timer, app); }		// Остановка таймера #1
	if (draw_timer != 0) { StopTimer(&draw_timer, app); }	// Остановка таймера #2
	ldrDisplayCbkUnReg((dispCbk)displayCbk);				// Удаление коллбека
	GDI_UnInit(&hDC);										// Деинициализация драйвера
	
	cprint("\x87" ELF_NAME ":\x83 Exit\n");

	// Завершаем работу приложения
	status = APP_ExitStateAndApp(ev_st, app, 0);

	// Выгружаем эльф
	return ldrUnloadElf(); 
}





// Обработчик события, EV_KEY_PRESS в данном случае
UINT32 HandleKeyPress( EVENT_STACK_T* ev_st,  APPLICATION_T* app ) {
	// Получаем код кнопки
 UINT8				key = GET_KEY(ev_st);
 UINT8              i;
 BOOL               change = true;
 BOOL	        	needintense = false, needrender = false, needkbd = false;
 KEY_CODES_T		keytopress = ReturnModeKey(&mode, key);
 
 for (i = KEY_PRESSED_LEN; i > 0 ; i--) {
  key_pressed[i] = key_pressed[i-1];
 }
 key_pressed[0] = key;
 
 if (key == key_toggle) {
  key_timer = StartTimer(key_timeout, KEY_TIMER_ID, ttSimple, app);
 } else {
  switch (mode) {
   case 1:
    if (keytopress != KEY_MULTIKEYS_PRESSED) {
     switch (keytopress) {
      case KEY_UP:
        if (intensity < 6) { intensity++; }
        needintense = true;
        break;
      case KEY_DOWN:
        if (intensity > 0) { intensity--; }
        needintense = true;
        break;
      case KEY_JOY_OK:
       switch (kbdlight) {
          case false:	kbdlight = true;	break;
          case true:	kbdlight = false;	break;
       }
       needkbd = true;
       break;
     }
    }
    APP_ConsumeEv( ev_st, app );
    break;
  }
 }
 
 if (needintense) {
     UIS_SetBacklightWithIntensity(255, intensity);
     text_count = 10;
 }
 if (needkbd) { DL_KeyUpdateKeypadBacklight(kbdlight); }

 return RESULT_OK;
}





// Обработчик события, EV_KEY_PRESS в данном случае
UINT32 HandleKeyRelease(EVENT_STACK_T* ev_st,  APPLICATION_T* app) {
	// Получаем код кнопки
 UINT8				key = GET_KEY(ev_st);
 KEY_CODES_T		keytorelease = ReturnModeKey(&mode, key);
 
 if (key == key_toggle) {
  if (key_pressed[0] == key_toggle) {
   StopTimer(&key_timer, app);
   key_pressed[0] = KEY_MULTIKEYS_PRESSED;
  } else {
   APP_ConsumeEv( ev_st, app );
  }
 } else {
  switch (mode) {
   case 1:
     APP_ConsumeEv( ev_st, app );
    break;
  }
 }
 
 return RESULT_OK;
}





// Функция обработки события таймера
UINT32 HandleTimerExpiried(EVENT_STACK_T* ev_st, APPLICATION_T* app) {
	// Получаем идентификатор таймера
 UINT32         tid = GET_TIMER_ID(ev_st);
 
 switch (tid) {
  case KEY_TIMER_ID:
   if (key_count==0) {
    if (key_pressed[0] == key_toggle) {
     APP_ConsumeEv( ev_st, app );
     ToggleMode(&mode);
    }
   }
   key_pressed[0] = KEY_MULTIKEYS_PRESSED;
   break;
  case DRAW_TIMER_ID:
   if (mode == 1) {
	GDI_BeginPaint(hDC, hDisp, hDraw);
    GDI_FillRect(hDC, 0, 0, 176, 220, cBg);
    if (text_count > 0) {
     drawLetter(hDC, 0, 200, 48+intensity, cFg, tCol, 2, 1);
     text_count--;
    }
	GDI_EndPaint(hDC, hDisp, hDraw);
   }
   APP_ConsumeEv( ev_st, app );
   break;
 }

 return RESULT_OK;
}





// PM API: Exit - выход из приложения через диспетчер задач
UINT32 HandleExit(EVENT_STACK_T* ev_st,  APPLICATION_T* app) {
	
	APP_ConsumeEv( ev_st, app );
	app->exit_status = TRUE;
	
	return RESULT_OK;
}





void displayCbk(const RECT_T* updatedRect) {
   if (mode == 1) {
	GDI_BeginPaint(hDC, hDisp, hDraw);
    GDI_FillRect(hDC, 0, 0, 176, 220, cBg);
    if (text_count > 0) {
     drawLetter(hDC, 0, 200, 48+intensity, cFg, tCol, 2, 1);
     text_count--;
    }
	GDI_EndPaint(hDC, hDisp, hDraw);
   }
	// Рисуем поверх UIS
}






UINT32 ToggleMode(UINT8 *wmode) {

 switch(*wmode) {
  case 0:
   *wmode = 1;
   break;
  case 1:
   *wmode = 0;
   UIS_ForceRefresh();
   //DL_KeyInjectKeyPress(key_toggle, KEY_RELEASE, KEY_PORTABLE_ID);
   //DL_KeyInjectKeyPress(KEY_RED, KEY_PRESS, KEY_PORTABLE_ID);
   //DL_KeyInjectKeyPress(KEY_RED, KEY_RELEASE, KEY_PORTABLE_ID);
   break;
 }
 
 return RESULT_OK;
}





KEY_CODES_T ReturnModeKey(UINT8 *wmode, UINT8 keycode) {

 UINT8				retcode = KEY_MULTIKEYS_PRESSED;

 switch(*wmode) {
  case 0:
   break;
  case 1:
   switch (keycode) {
    case KEY_UP:
    case KEY_2:   retcode = KEY_UP;			break;
    case KEY_DOWN:
    case KEY_8:   retcode = KEY_DOWN;		break;
    case KEY_JOY_OK:
    case KEY_5:   retcode = KEY_JOY_OK;	    break;
    default:    retcode = KEY_MULTIKEYS_PRESSED;
   }
   break;
 }

 return retcode;
}


// Конец файла. GAME OVER!